home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK2.toast / Development Kits (Disc 2) / OpenDoc / OpenDoc Development / Debugging Support / OpenDoc™ Source Code / Utilities / PlfmFile.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-28  |  52.1 KB  |  1,762 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        PlfmFile.cpp
  3.  
  4.     Contains:    Implmentation for PlatformFile class
  5.  
  6.     Owned by:    Vincent Lo
  7.  
  8.     Copyright:    © 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.         <10>     7/28/96    DH        Bug#1372834: Cyberdog: Drag to Finder fails
  13.                                     when MacOS scraptype used.
  14.          <9>      6/4/96    EL        Remove debug statement left in from last
  15.                                     check in.
  16.          <8>      6/4/96    EL        1289557: Truncate comment but don't split
  17.                                     two byte character if comment is too long.
  18.          <7>     5/31/96    JA        CW68K: Fixed mem leak/app-heap usage in
  19.                                     GetCustomIconFamily.
  20.          <6>     5/31/96    jpa        T10012: Added IsOpenDocDocument.
  21.          <5>     5/23/96    DH        1352221: Document Info dialog is
  22.                                     disabled/acts flaky. Fixed GetCustomIcon so
  23.                                     that it doesn't manually fiddle with the
  24.                                     resource fork of the file.
  25.          <4>      5/8/96    NP        1282265: saving as stationery looks like
  26.                                     document
  27.          <3>     3/15/96    DH        1329039 - OpenDoc's routine
  28.                                     PlatformFile::HasCustomIcon() does not
  29.                                     work.
  30.          <2>      3/1/96    JP        1314798: Made CreateResFile get type &
  31.                                     creator first
  32.  
  33.     To Do:
  34.     In Progress:
  35.         
  36. */
  37.  
  38. #ifndef _ODTYPES_
  39. #include "ODTypes.h"
  40. #endif
  41.  
  42. #ifndef _PLFMFILE_
  43. #include "PlfmFile.h"
  44. #endif
  45.  
  46. #ifndef _ODMEMORY_
  47. #include "ODMemory.h"
  48. #endif
  49.  
  50. #ifndef _EXCEPT_
  51. #include "Except.h"
  52. #endif
  53.  
  54. #ifndef _ODDEBUG_
  55. #include "ODDebug.h"
  56. #endif
  57.  
  58. #ifndef _PASCLSTR_
  59. #include "PasclStr.h"
  60. #endif
  61.  
  62. #ifndef _ITEXT_
  63. #include "IText.h"
  64. #endif
  65.  
  66. #ifndef _DOCUTILS_
  67. #include "DocUtils.h"
  68. #endif
  69.  
  70. #ifndef _DLOGUTIL_
  71. #include <DlogUtil.h>
  72. #endif
  73.  
  74. #ifndef _UTILDEFS_
  75. #include "UtilDefs.h"
  76. #endif
  77.  
  78. #ifndef _TEMPOBJ_
  79. #include "TempObj.h"
  80. #endif
  81.  
  82. #ifndef _UTILERRS_
  83. #include "UtilErrs.h"
  84. #endif
  85.  
  86. #ifndef __FILES__
  87. #include <Files.h>
  88. #endif
  89.  
  90. #ifndef __FOLDERS__
  91. #include <Folders.h>
  92. #endif
  93.  
  94. #ifndef __FINDER__
  95. #include <Finder.h>
  96. #endif
  97.  
  98. #ifndef __ICONS__
  99. #include <Icons.h>
  100. #endif
  101.  
  102. #ifndef __STRING__
  103. #include <string.h>
  104. #endif
  105.  
  106. #ifndef __ERRORS__
  107. #include <Errors.h>
  108. #endif
  109.  
  110. #ifndef __TEXTUTILS__
  111. #include "TextUtils.h"
  112. #endif
  113.  
  114. #ifndef _USERSRCM_
  115. #include <UseRsrcM.h>
  116. #endif
  117.  
  118. #ifndef __TEXTUTILS__
  119. #include "TextUtils.h"
  120. #endif
  121.  
  122. #include <ctype.h>    /* for islower( ) */
  123.  
  124.  
  125. #pragma segment PlatformFile
  126.  
  127. //==============================================================================
  128. // Constants
  129. //==============================================================================
  130.  
  131. const    ODSShort    kMaxFileNameSize        = 64;
  132. const    ODULong        kMaxCommentSize            = 199;
  133.  
  134. #define    kFileContainerType                    'ctyp'
  135. #define    kFileContainerTypeResID                1
  136.  
  137. const ODULong    kMaxCopyBufferSize            = 32 * 1024L;
  138. const ODULong    kMinCopyBufferSize            = 512;
  139.  
  140. static const ResType            kIconType[6] = {'ICN#','icl4','icl8','ics#','ics4','ics8'};
  141. static const short                kIconSize[6] = {256,   512,   1024,  64,    128,   256   };
  142.  
  143. #define kODCyberdogSignature                'dogz'
  144.  
  145. //==============================================================================
  146. // Scalar Types
  147. //==============================================================================
  148.  
  149. //==============================================================================
  150. // Local Classes
  151. //==============================================================================
  152.  
  153. //==============================================================================
  154. // Global Variables
  155. //==============================================================================
  156.  
  157. //==============================================================================
  158. // Function Prototype
  159. //==============================================================================
  160.  
  161. //==============================================================================
  162. // PlatformFile
  163. //==============================================================================
  164.  
  165. const ODOSType kBogusOSType = 0;    // Default type/creator value until it's read
  166.  
  167. //------------------------------------------------------------------------------
  168. // PlatformFile::PlatformFile
  169. //------------------------------------------------------------------------------
  170. PlatformFile::PlatformFile()
  171. {
  172.     fContainerType = kODNULL;
  173.     fCreator = kBogusOSType;
  174.     fFileType = kBogusOSType;
  175.     fScriptTag = smSystemScript;
  176.     
  177.     fFileSpec.vRefNum = 0;
  178.     fFileSpec.parID = 0;
  179.     fFileSpec.name[0] = 0;
  180.     fDataRefNum = 0;
  181.     fFileID = kODNoFileID;
  182.     fPermission = fsCurPerm;
  183.     fResRefNum = kODNoFileRefNum;
  184.     fResOpenStack = 0;
  185.     fNeedToClose = kODFalse;
  186.     
  187.     fVolModDate = fTimeLastChecked = 0;
  188. }
  189.  
  190. //------------------------------------------------------------------------------
  191. // PlatformFile::~PlatformFile
  192. //------------------------------------------------------------------------------
  193. PlatformFile::~PlatformFile()
  194. {
  195.     ODDisposePtr(fContainerType);
  196. }
  197.  
  198. //------------------------------------------------------------------------------
  199. // PlatformFile::Specify
  200. //------------------------------------------------------------------------------
  201. void PlatformFile::Specify(const ODFileSpec* fileSpec)
  202. {
  203.     fFileSpec = *fileSpec;
  204.     fCreator = kBogusOSType;
  205.     fFileType = kBogusOSType;
  206.     fFileID = kODNoFileID;
  207. }
  208.  
  209. void PlatformFile::SpecifyFromFile(PlatformFile* file)
  210. {
  211.     const ODFileSpec &fileSpec = file->GetFileSpec();
  212.     this->Specify(&fileSpec);
  213. }
  214.  
  215. //------------------------------------------------------------------------------
  216. // PlatformFile::SetAsciiname
  217. //------------------------------------------------------------------------------
  218. void PlatformFile::SetAsciiName(const char* asciiName)
  219. {
  220.     ODSByte pname[kMaxFileNameSize+1];
  221.     strncpy(pname,asciiName,kMaxFileNameSize);
  222.     pname[kMaxFileNameSize] = 0;
  223.     
  224.     CToPascalString(pname);
  225.     if (fFileSpec.vRefNum == 0 &&
  226.         fFileSpec.parID == 0 &&
  227.         fFileSpec.name[0] == 0)
  228.     {
  229.         FSMakeFSSpec(0, 0, (StringPtr)pname, &fFileSpec);
  230.     }
  231.     else
  232.     {
  233.         CopyPascalString(fFileSpec.name,(StringPtr)pname);
  234.     }    
  235.     this->Specify(&fFileSpec);
  236. }
  237.  
  238. //------------------------------------------------------------------------------
  239. // PlatformFile::IsLocked
  240. //------------------------------------------------------------------------------
  241. ODBoolean PlatformFile::IsLocked()
  242. {
  243.     CInfoPBRec    pbBlock;
  244.     ODBoolean    result = kODFalse;
  245.  
  246.     // Check to see whether the volume is locked
  247.  
  248.     // Eric's original code with slight modifications.
  249.     // Appears to be needed in the case of a locked floppy. -TÇ
  250.     HParamBlockRec pb;
  251.     pb.volumeParam.ioCompletion = kODNULL;
  252.     pb.volumeParam.ioNamePtr = kODNULL;
  253.     pb.volumeParam.ioVRefNum = fFileSpec.vRefNum;
  254.     pb.volumeParam.ioVolIndex = 0;
  255.  
  256.     THROW_IF_ERROR(PBHGetVInfoSync(&pb));
  257.  
  258.     // <eeh> I have no clue if this "0x80"is right!!!  Find out what
  259.     // the constant is for write-access possible....
  260.  
  261.     result = (pb.volumeParam.ioVAtrb & 0x80) ? kODTrue : kODFalse;
  262.  
  263.     // Check to see whether the directory is locked
  264.     if (result == kODFalse) {
  265.         // first assume it is a file share volume
  266.         HParamBlockRec    paramBlk;
  267.         paramBlk.accessParam.ioCompletion = kODNULL;
  268.         paramBlk.accessParam.ioNamePtr = kODNULL;
  269.         paramBlk.accessParam.ioVRefNum = fFileSpec.vRefNum;
  270.         paramBlk.accessParam.ioDirID = fFileSpec.parID;
  271.         paramBlk.accessParam.ioACAccess = 0;
  272.         OSErr err = PBHGetDirAccessSync(¶mBlk);
  273.         
  274.         if (err == noErr) {        /* it is a file share volume, look at the access right */
  275.             if ((paramBlk.accessParam.ioACAccess & 0x04000000) == 0) /* no write access */
  276.                 result = kODTrue;
  277.         }
  278.         else if (err == paramErr) { /* it is not file share, look at directory */
  279.             pbBlock.dirInfo.ioCompletion = kODNULL;
  280.             pbBlock.dirInfo.ioNamePtr = kODNULL;
  281.             pbBlock.dirInfo.ioVRefNum = fFileSpec.vRefNum;
  282.             pbBlock.dirInfo.ioFDirIndex = -1;
  283.             pbBlock.dirInfo.ioDrDirID = fFileSpec.parID;
  284.             pbBlock.dirInfo.ioFlAttrib = 0;
  285.             THROW_IF_ERROR(PBGetCatInfoSync(&pbBlock));
  286.             if (pbBlock.dirInfo.ioFlAttrib & 1)
  287.                 result = kODTrue;
  288.         }
  289.         else
  290.             THROW(err);
  291.     }
  292.  
  293.     // Check to see whether the file is locked
  294.     if (result == kODFalse) {    
  295.         pbBlock.hFileInfo.ioCompletion = kODNULL;
  296.         pbBlock.hFileInfo.ioFDirIndex = 0;
  297.         pbBlock.hFileInfo.ioNamePtr = fFileSpec.name;
  298.         pbBlock.hFileInfo.ioVRefNum = fFileSpec.vRefNum;
  299.         pbBlock.hFileInfo.ioDirID = fFileSpec.parID;
  300.         
  301.         THROW_IF_ERROR(PBGetCatInfoSync(&pbBlock));
  302.  
  303.         if (pbBlock.hFileInfo.ioFlAttrib & 1)
  304.             result = kODTrue;
  305.     }
  306.     
  307.     return result;
  308. }
  309.  
  310. //------------------------------------------------------------------------------
  311. // PlatformFile::Lock
  312. //------------------------------------------------------------------------------
  313. void PlatformFile::Lock()
  314. {
  315.     THROW_IF_ERROR( FSpSetFLock(&fFileSpec) );
  316. }
  317.  
  318. //------------------------------------------------------------------------------
  319. // PlatformFile::Unlock
  320. //------------------------------------------------------------------------------
  321. void PlatformFile::Unlock()
  322. {
  323.     THROW_IF_ERROR( FSpRstFLock(&fFileSpec) );
  324. }
  325.  
  326.  
  327. //------------------------------------------------------------------------------
  328. // PlatformFile::IsStationery
  329. //------------------------------------------------------------------------------
  330. ODBoolean PlatformFile::IsStationery()
  331. {
  332.     FInfo fileInfo;
  333.     THROW_IF_ERROR( FSpGetFInfo(&fFileSpec,&fileInfo) );
  334.     return (((fileInfo.fdFlags)&kIsStationary)!=0);
  335. }
  336.  
  337. //------------------------------------------------------------------------------
  338. // PlatformFile::SetStationery
  339. //------------------------------------------------------------------------------
  340.  
  341. void PlatformFile::SetStationery(ODBoolean isStationery)
  342. {
  343.     if (isStationery)
  344.         this->SetFinderFlag(kIsStationery);
  345.     else
  346.         this->UnsetFinderFlag(kIsStationery);
  347.  
  348. //    FInfo fileInfo;
  349.  
  350. //    THROW_IF_ERROR( FSpGetFInfo(&fFileSpec,&fileInfo) );
  351. //    if (isStationery)
  352. //        (fileInfo.fdFlags) |= kIsStationery;
  353. //    else
  354. //        (fileInfo.fdFlags) &= ~kIsStationery;
  355. //    THROW_IF_ERROR( FSpSetFInfo(&fFileSpec,&fileInfo) );
  356.     // Finder bug prevents this from helping to update the icon in the Finder
  357. //    BumpFolderModDate();
  358. }
  359.  
  360. //------------------------------------------------------------------------------
  361. // PlatformFile::SetCustomIcon
  362. //------------------------------------------------------------------------------
  363.  
  364. void PlatformFile::SetCustomIcon(ODBoolean hasCustomIcon)
  365. {
  366.     if (hasCustomIcon)
  367.         this->SetFinderFlag(kHasCustomIcon);
  368.     else
  369.         this->UnsetFinderFlag(kHasCustomIcon);
  370. //    FInfo fileInfo;
  371.  
  372. //    THROW_IF_ERROR( FSpGetFInfo(&fFileSpec, &fileInfo) );
  373. //    if (hasCustomIcon)
  374. //        (fileInfo.fdFlags) |= kHasCustomIcon;
  375. //    else
  376. //        (fileInfo.fdFlags) &= ~kHasCustomIcon;
  377. //    THROW_IF_ERROR( FSpSetFInfo(&fFileSpec, &fileInfo) );
  378. //    BumpFolderModDate();
  379. }
  380.  
  381. //------------------------------------------------------------------------------
  382. // PlatformFile::SetFinderFlag
  383. //------------------------------------------------------------------------------
  384.  
  385. void PlatformFile::SetFinderFlag(ODUShort flag)
  386. {
  387.     FInfo fileInfo;
  388.  
  389.     THROW_IF_ERROR( FSpGetFInfo(&fFileSpec, &fileInfo) );
  390.     (fileInfo.fdFlags) |= flag;
  391.     THROW_IF_ERROR( FSpSetFInfo(&fFileSpec, &fileInfo) );
  392. //    if (flag != kIsStationery)
  393.         BumpFolderModDate();
  394. }
  395.  
  396. //------------------------------------------------------------------------------
  397. // PlatformFile::UnsetFinderFlag
  398. //------------------------------------------------------------------------------
  399.  
  400. void PlatformFile::UnsetFinderFlag(ODUShort flag)
  401. {
  402.     FInfo fileInfo;
  403.  
  404.     THROW_IF_ERROR( FSpGetFInfo(&fFileSpec, &fileInfo) );
  405.     (fileInfo.fdFlags) &= ~flag;
  406.     THROW_IF_ERROR( FSpSetFInfo(&fFileSpec, &fileInfo) );
  407. //    if (flag != kIsStationery)
  408.         BumpFolderModDate();
  409. }
  410.  
  411. //------------------------------------------------------------------------------
  412. // PlatformFile::HasCustomIcon
  413. //------------------------------------------------------------------------------
  414.  
  415. ODBoolean PlatformFile::HasCustomIcon()
  416. {
  417.     FInfo fileInfo;
  418.     
  419.     THROW_IF_ERROR( FSpGetFInfo(&fFileSpec, &fileInfo) );
  420.     return ( (fileInfo.fdFlags & kHasCustomIcon) ? kODTrue : kODFalse);
  421. }
  422.  
  423. //------------------------------------------------------------------------------
  424. // PlatformFile::IsDirectory
  425. //------------------------------------------------------------------------------
  426. ODBoolean PlatformFile::IsDirectory()
  427. {    
  428.     ODBoolean isDirectory = kODFalse;
  429.     
  430.     if( fFileID == kODNoFileID ) {
  431.         CInfoPBRec    pbBlock;
  432.         pbBlock.hFileInfo.ioCompletion = kODNULL;
  433.         pbBlock.hFileInfo.ioFDirIndex = 0;
  434.         pbBlock.hFileInfo.ioNamePtr = fFileSpec.name;
  435.         pbBlock.hFileInfo.ioVRefNum = fFileSpec.vRefNum;
  436.         pbBlock.hFileInfo.ioDirID = fFileSpec.parID;
  437.         THROW_IF_ERROR(PBGetCatInfoSync(&pbBlock));
  438.         isDirectory = pbBlock.dirInfo.ioFlAttrib & 0x10 ? kODTrue : kODFalse;
  439.     }
  440.     return isDirectory;
  441. }
  442.  
  443. //------------------------------------------------------------------------------
  444. // PlatformFile::IsEqualTo
  445. //------------------------------------------------------------------------------
  446. ODBoolean PlatformFile::IsEqualTo(PlatformFile* file)
  447. {
  448.     return (fFileSpec.parID == file->fFileSpec.parID &&
  449.             fFileSpec.vRefNum == file->fFileSpec.vRefNum &&
  450.             EqualPascalStrings(fFileSpec.name, file->fFileSpec.name));
  451. }
  452.  
  453. //------------------------------------------------------------------------------
  454. // PlatformFile::GetFInfoFlags
  455. //------------------------------------------------------------------------------
  456. ODUShort    PlatformFile::GetFInfoFlags()
  457. {
  458.     FInfo fileInfo;
  459.  
  460.     THROW_IF_ERROR( FSpGetFInfo(&fFileSpec, &fileInfo) );
  461.     return fileInfo.fdFlags;
  462. }
  463.  
  464. //------------------------------------------------------------------------------
  465. // PlatformFile::Create
  466. //------------------------------------------------------------------------------
  467. void PlatformFile::Create(ODOSType creator, ODOSType fileType, ODScriptCode scriptCode)
  468. {    
  469.     
  470.     if (fDataRefNum == kODNoFileRefNum) {
  471.         THROW_IF_ERROR( FSpCreate(&fFileSpec, creator, fileType, scriptCode) );
  472.     }
  473.     fCreator = creator;
  474.     fFileType = fileType;
  475.     fScriptTag = scriptCode;
  476.     
  477.     this->GetFileID();
  478. }
  479.  
  480. //------------------------------------------------------------------------------
  481. // PlatformFile::CreateResFile
  482. //------------------------------------------------------------------------------
  483. void PlatformFile::CreateResFile()
  484. {
  485.     if (fResRefNum == kODNoFileRefNum)
  486.     {
  487.         this->GetPlatformType();    // make sure the type and creator are known
  488.         FSpCreateResFile(&fFileSpec, fCreator, fFileType, fScriptTag);
  489.         THROW_IF_ERROR(ResError());
  490.     }
  491.     this->GetFileID();
  492. }
  493.  
  494. //------------------------------------------------------------------------------
  495. // PlatformFile::OpenResFile
  496. //------------------------------------------------------------------------------
  497. void PlatformFile::OpenResFile()
  498. {
  499.     ASSERT(fResOpenStack >= 0, kODErrAssertionFailed);
  500.     if (fResRefNum == kODNoFileRefNum)
  501.     {
  502.         ASSERT(fResOpenStack == 0, fResOpenStack);
  503.         fResRefNum = GetFirstLocalPath(PlatformFile::kODResourceFork);
  504.         if (fResRefNum != kODNoFileRefNum)
  505.         {
  506.             // Resource fork is already open
  507.             UseResFile(fResRefNum);
  508.             fNeedToClose = kODFalse;
  509.         }
  510.         else
  511.         {
  512.             // Resource fork is closed
  513.             fResRefNum = FSpOpenResFile(&fFileSpec, fPermission);
  514.             if (fResRefNum == -1 && fPermission != fsRdPerm)
  515.             {
  516.                 fResRefNum = kODNoFileRefNum;
  517.                 CreateResFile();
  518.                 fResRefNum = FSpOpenResFile(&fFileSpec, fPermission);
  519.             }
  520.             OSErr err = ResError();
  521.             if (err != eofErr)
  522.             {
  523.                 if (fResRefNum == -1)
  524.                     fResRefNum = kODNoFileRefNum;
  525.                 THROW_IF_ERROR(ResError());
  526.             }
  527.             if (fResRefNum == -1)
  528.             {
  529.                 fResRefNum = kODNoFileRefNum;
  530.                 THROW(resFNotFound);
  531.             }
  532.             fNeedToClose = kODTrue;
  533.         }
  534.     }
  535.     else
  536.         UseResFile(fResRefNum);
  537.     ++fResOpenStack;
  538. }
  539.  
  540. //------------------------------------------------------------------------------
  541. // PlatformFile::CloseResFile
  542. //------------------------------------------------------------------------------
  543. void PlatformFile::CloseResFile()
  544. {
  545.     ASSERT(fResOpenStack > 0, fResOpenStack);
  546.     if (--fResOpenStack == 0 && fNeedToClose)
  547.     {
  548.         ::CloseResFile(fResRefNum);
  549.         THROW_IF_ERROR(ResError());
  550.         fResRefNum = kODNoFileRefNum;
  551.     }
  552. }
  553.  
  554. //------------------------------------------------------------------------------
  555. // PlatformFile::GetFileID
  556. //------------------------------------------------------------------------------
  557. void PlatformFile::GetFileID()
  558. {
  559.     if( fFileID == kODNoFileID ) {
  560.         CInfoPBRec    pbBlock;
  561.         pbBlock.hFileInfo.ioCompletion = kODNULL;
  562.         pbBlock.hFileInfo.ioFDirIndex = 0;
  563.         pbBlock.hFileInfo.ioNamePtr = fFileSpec.name;
  564.         pbBlock.hFileInfo.ioVRefNum = fFileSpec.vRefNum;
  565.         pbBlock.hFileInfo.ioDirID = fFileSpec.parID;
  566.         THROW_IF_ERROR(PBGetCatInfoSync(&pbBlock));
  567.         fFileID = pbBlock.hFileInfo.ioDirID;    /* for tracking the file later */
  568.     }
  569. }
  570.  
  571. //------------------------------------------------------------------------------
  572. // PlatformFile::UpdateSpecFromID
  573. //------------------------------------------------------------------------------
  574. void PlatformFile::UpdateSpecFromID()
  575. {
  576.     if (fFileID != kODNoFileID) {    /* make sure got the latest name in file spec */
  577.         HParamBlockRec hPB;
  578.         hPB.fidParam.ioCompletion = kODNULL;
  579.         hPB.fidParam.ioNamePtr = fFileSpec.name;
  580.         hPB.fidParam.ioVRefNum = fFileSpec.vRefNum;
  581.         hPB.fidParam.ioFileID = fFileID;
  582.         if (PBResolveFileIDRefSync(&hPB) == noErr)    /* ignore any error */
  583.             fFileSpec.parID = hPB.fidParam.ioSrcDirID;
  584.     }
  585. }
  586.  
  587.  
  588. //------------------------------------------------------------------------------
  589. // PlatformFile::Exists
  590. //------------------------------------------------------------------------------
  591. ODBoolean PlatformFile::Exists()
  592. {
  593.     const ODFileSpec &filespec = this->GetFileSpec();
  594.     FInfo ignore ;
  595.     OSErr err = FSpGetFInfo( &filespec, &ignore );
  596.     if ( err == noErr )
  597.         return kODTrue ;
  598.     else {
  599.         if ( err != fnfErr )
  600.             THROW( err );
  601.         return kODFalse ;
  602.     }
  603. }
  604.  
  605. //------------------------------------------------------------------------------
  606. // PlatformFile::Open
  607. //------------------------------------------------------------------------------
  608. void PlatformFile::Open()
  609. {    
  610.     if (fDataRefNum == kODNoFileRefNum) {
  611.         this->GetFileID();
  612.         THROW_IF_ERROR(FSpOpenDF(&fFileSpec, fPermission, &fDataRefNum));
  613.     }
  614.     else
  615.         THROW(kODErrFileOpened);
  616. }
  617.  
  618. //------------------------------------------------------------------------------
  619. // PlatformFile::Close
  620. //------------------------------------------------------------------------------
  621. void PlatformFile::Close()
  622. {    
  623.     if (fDataRefNum != kODNoFileRefNum) {
  624.         THROW_IF_ERROR(FSClose(fDataRefNum));
  625.         fDataRefNum = kODNoFileRefNum;
  626.     }
  627.     else
  628.         THROW(kODErrFileClosed);
  629. }
  630.  
  631. //------------------------------------------------------------------------------
  632. // PlatformFile::Delete
  633. //------------------------------------------------------------------------------
  634. void PlatformFile::Delete()
  635. {    
  636.     THROW_IF_ERROR(FSpDelete(&fFileSpec));
  637.     fFileID = kODNoFileID;
  638. }
  639.  
  640.  
  641. //------------------------------------------------------------------------------
  642. // PlatformFile::FlushVolume
  643. //------------------------------------------------------------------------------
  644. void PlatformFile::FlushVolume()
  645. {    
  646.     if (fDataRefNum != kODNoFileRefNum) {
  647.         ParamBlockRec    pb;
  648.     
  649.         pb.ioParam.ioCompletion = kODNULL;
  650.         pb.ioParam.ioRefNum = fDataRefNum;
  651.         (void) PBFlushFileSync(&pb);
  652.     }
  653.  
  654.     (void) FlushVol(kODNULL, fFileSpec.vRefNum);
  655. }
  656.  
  657. //------------------------------------------------------------------------------
  658. // PlatformFile::SetFilePos
  659. //------------------------------------------------------------------------------
  660. void PlatformFile::SetFilePos(ODSShort posMode, ODSLong posOff)
  661. {    
  662.     THROW_IF_ERROR(SetFPos(fDataRefNum, posMode, posOff));
  663. }
  664.  
  665. //------------------------------------------------------------------------------
  666. // PlatformFile::GetFilePos
  667. //------------------------------------------------------------------------------
  668. ODSLong PlatformFile::GetFilePos()
  669. {
  670.     ODSLong    posOff;
  671.     
  672.     THROW_IF_ERROR(GetFPos(fDataRefNum, &posOff));
  673.     return posOff;
  674. }
  675.  
  676. //------------------------------------------------------------------------------
  677. // PlatformFile::Read
  678. //------------------------------------------------------------------------------
  679. void PlatformFile::Read(void* buffer, ODSLong* count)
  680. {    
  681.     THROW_IF_ERROR(FSRead(fDataRefNum, count, buffer));
  682. }
  683.  
  684. //------------------------------------------------------------------------------
  685. // PlatformFile::Write
  686. //------------------------------------------------------------------------------
  687. void PlatformFile::Write(const void* buffer, ODSLong* count)
  688. {    
  689.     THROW_IF_ERROR(FSWrite(fDataRefNum, count, buffer));
  690. }
  691.  
  692. //------------------------------------------------------------------------------
  693. // PlatformFile::GetEndOfFile
  694. //------------------------------------------------------------------------------
  695. ODSLong PlatformFile::GetEndOfFile()
  696. {    
  697.     ODSLong    length;
  698.     
  699.     THROW_IF_ERROR(GetEOF(fDataRefNum, &length));
  700.     return length;
  701. }
  702.  
  703. //------------------------------------------------------------------------------
  704. // PlatformFile::SetEndOfFile
  705. //------------------------------------------------------------------------------
  706. void  PlatformFile::SetEndOfFile(ODSLong length)
  707. {    
  708.     THROW_IF_ERROR(SetEOF(fDataRefNum, length));
  709. }
  710.  
  711. //------------------------------------------------------------------------------
  712. // PlatformFile::GetName
  713. //------------------------------------------------------------------------------
  714. ODName* PlatformFile::GetName()
  715. {
  716.     this->UpdateSpecFromID();
  717.  
  718.     return CreateIText(fScriptTag, 0, fFileSpec.name);
  719. }
  720.  
  721. //------------------------------------------------------------------------------
  722. // PlatformFile::GetAsciiName
  723. //------------------------------------------------------------------------------
  724. void PlatformFile::GetAsciiName(char* asciiName, ODULong maxLength)
  725. {
  726.     this->UpdateSpecFromID();
  727.  
  728.     ODULong n = fFileSpec.name[0];
  729.     if( n > maxLength )
  730.         n = maxLength;
  731.     ODBlockMove(&(fFileSpec.name[1]), asciiName, n);
  732.     asciiName[n] = '\0';
  733. }
  734.  
  735. //------------------------------------------------------------------------------
  736. // PlatformFile::GetPlatformCreator
  737. //------------------------------------------------------------------------------
  738. ODOSType PlatformFile::GetPlatformCreator()
  739. {
  740.     if (fCreator == kBogusOSType) {
  741.         FInfo    fileInfo;
  742.         THROW_IF_ERROR(FSpGetFInfo(&fFileSpec, &fileInfo));
  743.         fCreator = fileInfo.fdCreator;
  744.         fFileType = fileInfo.fdType;
  745.     }
  746.     return fCreator;
  747. }    
  748.  
  749. //------------------------------------------------------------------------------
  750. // PlatformFile::SetPlatformCreator
  751. //------------------------------------------------------------------------------
  752. void PlatformFile::SetPlatformCreator(ODOSType creator)
  753. {
  754.     FInfo    fileInfo;
  755.     THROW_IF_ERROR(FSpGetFInfo(&fFileSpec, &fileInfo));
  756.     if( fileInfo.fdCreator != creator ) {
  757.         fileInfo.fdCreator = creator;
  758.         THROW_IF_ERROR(FSpSetFInfo(&fFileSpec, &fileInfo));
  759.         fCreator = creator;
  760.         this->BumpFolderModDate();
  761.     }
  762. }    
  763.  
  764. //------------------------------------------------------------------------------
  765. // PlatformFile::GetPlatformType
  766. //------------------------------------------------------------------------------
  767. ODOSType PlatformFile::GetPlatformType()
  768. {
  769.     if (fFileType == kBogusOSType) {
  770.         FInfo    fileInfo;
  771.         THROW_IF_ERROR(FSpGetFInfo(&fFileSpec, &fileInfo));
  772.         fCreator = fileInfo.fdCreator;
  773.         fFileType = fileInfo.fdType;
  774.     }
  775.     return fFileType;
  776. }    
  777.  
  778. //------------------------------------------------------------------------------
  779. // PlatformFile::SetPlatformType
  780. //------------------------------------------------------------------------------
  781. void PlatformFile::SetPlatformType(ODOSType fileType)
  782. {
  783.     FInfo    fileInfo;
  784.     THROW_IF_ERROR(FSpGetFInfo(&fFileSpec, &fileInfo));
  785.     if( fileInfo.fdType != fileType ) {
  786.         fileInfo.fdType = fileType;
  787.         THROW_IF_ERROR(FSpSetFInfo(&fFileSpec, &fileInfo));
  788.         fFileType = fileType;
  789.         this->BumpFolderModDate();
  790.     }
  791. }    
  792.  
  793. //------------------------------------------------------------------------------
  794. // PlatformFile::IsOpenDocDocument
  795. //------------------------------------------------------------------------------
  796. ODBoolean    PlatformFile::IsOpenDocDocument( )
  797. {
  798.     return IsOpenDocDocument(this->GetPlatformType(),this->GetPlatformCreator());
  799. }
  800.  
  801. ODBoolean
  802. PlatformFile::IsOpenDocDocument( OSType type, OSType creator ) /* static method */
  803. {
  804.     /*    In OpenDoc 1.0, all documents had 'odtm' as their creator. To support
  805.         CyberDog and container applications, we need to allow other creators.
  806.         To support this, we define a space of filetypes that are known to be
  807.         OpenDoc containers. The first (high-order) byte of the filetype is
  808.         a magic constant value. */
  809.     
  810.     // There's some big-endian fu here but this is Mac specific code anyway.
  811.     
  812.     if( (type>>24)==kODMagicFileTypeChar )
  813.         return true;
  814.     if( ( creator==kODShellSignature || creator==kODCyberdogSignature ) && type!='APPL' && type!='shlb' )
  815.         if( !( (type>>8)=='edt' && islower(type&0xFF) ) )    // not an edition file
  816.             return true;
  817.     return false;
  818. }
  819.  
  820.  
  821. //------------------------------------------------------------------------------
  822. // PlatformFile::GetContainerType
  823. //------------------------------------------------------------------------------
  824.  
  825. ODContainerType PlatformFile::GetContainerType()
  826. {
  827.     if (fContainerType == kODNULL)
  828.         fContainerType =
  829.             (ODContainerType)
  830.             (this->ReadResourcePtr(kFileContainerType, kFileContainerTypeResID, kODNULL));
  831.  
  832.     return fContainerType;
  833. }
  834.  
  835. //------------------------------------------------------------------------------
  836. // PlatformFile::SetContainerType
  837. //------------------------------------------------------------------------------
  838.  
  839. void PlatformFile::SetContainerType(ODContainerType containerType)
  840. {
  841.     ODDisposePtr(fContainerType);
  842.     fContainerType = containerType;
  843.  
  844.     this->WriteResourcePtr(kFileContainerType, kFileContainerTypeResID, 
  845.                         (ODPtr)containerType, strlen(containerType)+1);
  846. }
  847.  
  848.  
  849. //------------------------------------------------------------------------------
  850. // CWithActiveResources class
  851. //------------------------------------------------------------------------------
  852.  
  853. class CWithActiveResources :Destructo {
  854.     public:
  855.     CWithActiveResources( PlatformFile* );
  856.    ~CWithActiveResources( );
  857.     private:
  858.     PlatformFile    *fFile;
  859.     ODFileRefNum    fCurResFile;
  860.     ODBoolean        fSuccessfullyOpened;
  861. };
  862.  
  863. CWithActiveResources::CWithActiveResources( PlatformFile *pf )
  864. {
  865.     fSuccessfullyOpened = kODFalse;
  866.     fFile = pf;
  867.     fCurResFile = CurResFile();
  868.     fFile->OpenResFile();
  869.     fSuccessfullyOpened = kODTrue;
  870. }
  871.  
  872. CWithActiveResources::~CWithActiveResources( )
  873. {
  874.     if (fSuccessfullyOpened)
  875.         fFile->CloseResFile();
  876.     UseResFile(fCurResFile);
  877. }
  878.         
  879.  
  880. //------------------------------------------------------------------------------
  881. // PlatformFile::ReadResourcePtr
  882. //------------------------------------------------------------------------------
  883. ODPtr PlatformFile::ReadResourcePtr(ODPlatformType resType, ODSShort resID, ODULong* size)
  884. {
  885.     ODPtr resPtr = kODNULL;
  886.     
  887.     TRY
  888.         CWithActiveResources w(this); // this throws if no resfile
  889.         
  890.         Handle resHandle = Get1Resource(resType, resID);
  891.         if (resHandle != kODNULL)
  892.         {
  893.             HNoPurge(resHandle);
  894.             ODULong hsize = GetHandleSize(resHandle);
  895.             if (size != kODNULL)
  896.                 *size = hsize;
  897.             resPtr = ODNewPtrClear(hsize,0);
  898.             ODBlockMove(*resHandle,resPtr, hsize);
  899.             ReleaseResource(resHandle);
  900.         } else if( ResError() != resNotFound )
  901.             THROW_IF_ERROR(ResError());
  902.  
  903.     CATCH_ALL
  904.     ENDTRY
  905.     
  906.     return resPtr;  // Method Specific
  907. }
  908.  
  909. //------------------------------------------------------------------------------
  910. // PlatformFile::WriteResourcePtr
  911. //------------------------------------------------------------------------------
  912. void PlatformFile::WriteResourcePtr(ODPlatformType resType, ODSShort resID, 
  913.                                     const void *resPtr, ODULong size)
  914. {
  915.     ASSERT(resPtr!=kODNULL,kODErrIllegalNullInput);
  916.     
  917.     SetPermission(fsRdWrPerm);
  918.     CWithActiveResources w(this);
  919.     
  920.     Handle resHandle = Get1Resource(resType,resID);
  921.     if( ResError() != resNotFound )
  922.         THROW_IF_ERROR(ResError());
  923.         
  924.     ODBoolean needsAdding = (resHandle == kODNULL);
  925.     if (needsAdding)
  926.         resHandle = ODNewHandle(size);
  927.     else {
  928.         HNoPurge(resHandle);
  929.         ODSetHandleSize(resHandle, size);
  930.     }
  931.     
  932.     ODBlockMove(resPtr,*resHandle, size);
  933.     
  934.     if (needsAdding)
  935.         AddResource(resHandle,resType,resID,"\p");
  936.     else
  937.         ChangedResource(resHandle);
  938.     THROW_IF_ERROR(ResError());
  939. }
  940.  
  941.  
  942. //------------------------------------------------------------------------------
  943. // PlatformFile::DeleteResource
  944. //------------------------------------------------------------------------------
  945. void PlatformFile::DeleteResource(ODPlatformType resType, ODSShort resID)
  946. {
  947.     SetPermission(fsRdWrPerm);
  948.     CWithActiveResources w(this);
  949.  
  950.     Handle resHandle = Get1Resource(resType, resID);
  951.     OSErr err= ResError();
  952.     if( resHandle ) {
  953.         RemoveResource(resHandle);
  954.         err= ResError();
  955.         if( !err )
  956.             DisposeHandle(resHandle);    // After RemoveResource it's not a rsrc
  957.     } else {
  958.         if( err == resNotFound )
  959.             err = noErr;
  960.     }
  961.     THROW_IF_ERROR(err);
  962. }
  963.  
  964. //------------------------------------------------------------------------------
  965. // PlatformFile::GetAllocationBlockSize
  966. //------------------------------------------------------------------------------
  967. ODULong PlatformFile::GetAllocationBlockSize()
  968. {
  969.     HParamBlockRec pb;
  970.     
  971.     pb.volumeParam.ioCompletion = kODNULL;
  972.     pb.volumeParam.ioNamePtr = kODNULL;
  973.     pb.volumeParam.ioVRefNum = fFileSpec.vRefNum;
  974.     pb.volumeParam.ioVolIndex = 0;
  975.  
  976.     THROW_IF_ERROR(PBHGetVInfoSync(&pb));
  977.  
  978.     return pb.volumeParam.ioVAlBlkSiz;
  979. }
  980.  
  981. //------------------------------------------------------------------------------
  982. // PlatformFile::CopyFrom
  983. //------------------------------------------------------------------------------
  984. void PlatformFile::CopyFrom( PlatformFile* src )
  985. {
  986.     ODBoolean srcIsOpen = (src->GetFileRefNum() != kODNoFileRefNum);
  987.     if ( !srcIsOpen )
  988.         src->Open();
  989.     this->SetPermission( fsRdWrPerm );        // currently this is the default value
  990.     if (!this->Exists())
  991.         this->Create(src->GetPlatformCreator(), src->GetPlatformType(), 0 /*$$$$$ scriptcode?*/);
  992.  
  993.     this->Open();
  994.             
  995.     src->SetFilePos( fsFromStart, 0 );
  996.     this->SetFilePos( fsFromStart, 0 );
  997.     
  998.     ODSLong bytesLeft = src->GetEndOfFile();
  999.  
  1000.     TempODHandle hbuffer = kODNULL;
  1001.     ODSLong bufferSize = kMaxCopyBufferSize;
  1002.     if( bufferSize > bytesLeft )
  1003.         bufferSize = bytesLeft;
  1004.     for( ; bufferSize>=kMinCopyBufferSize; bufferSize /= 2 ) {
  1005.         OSErr err;
  1006.         hbuffer= TempNewHandle(bufferSize,&err);
  1007.         if( hbuffer ) break;
  1008.     }
  1009.     WASSERT(bufferSize > 0);
  1010.     THROW_IF_NULL(hbuffer);
  1011.     void *buffer = *hbuffer;
  1012.     
  1013.     ODSLong count;
  1014.  
  1015.     while( bytesLeft > 0 )
  1016.     {
  1017.         count = bytesLeft < bufferSize? bytesLeft: bufferSize ;
  1018.         WASSERT(count > 0);
  1019.         src->Read( buffer, &count );
  1020.         this->Write( buffer, &count );
  1021.         bytesLeft -= count ;
  1022.     }
  1023.     
  1024.     if ( !srcIsOpen )
  1025.         src->Close();
  1026.     this->Close();
  1027. }
  1028.  
  1029. //------------------------------------------------------------------------------
  1030. // PlatformFile::MoveRename
  1031. //------------------------------------------------------------------------------
  1032. void PlatformFile::MoveRename( ODFileSpec* newSpec, ODBoolean isDuplicate )
  1033. {
  1034.     // This will fail if a file with the old name already exists in the
  1035.     // target directory. MoreFiles (DTS) has a more robust version of this.
  1036.     
  1037.     ASSERT(newSpec->vRefNum == fFileSpec.vRefNum, kODErrAssertionFailed);
  1038.  
  1039.     if ( isDuplicate )
  1040.     {
  1041.         THROW_IF_ERROR( FSpDelete( newSpec ) ); 
  1042.     }
  1043.  
  1044.     this->Move( newSpec->parID );
  1045.     this->Rename( newSpec->name );
  1046. }    // MoveRename()
  1047.  
  1048.  
  1049. //------------------------------------------------------------------------------
  1050. // PlatformFile::Move
  1051. //------------------------------------------------------------------------------
  1052.  
  1053. void PlatformFile::Move( ODSLong targetParID )
  1054. {
  1055.     CMovePBRec paramBlock ;
  1056.     memset( ¶mBlock, 0, sizeof(paramBlock) );
  1057.     
  1058.     paramBlock.ioNamePtr = fFileSpec.name ;
  1059.     paramBlock.ioVRefNum = fFileSpec.vRefNum ;
  1060.     paramBlock.ioNewDirID = targetParID ;
  1061.     paramBlock.ioDirID = fFileSpec.parID ;
  1062.     
  1063.     (void) HDelete(fFileSpec.vRefNum,targetParID,fFileSpec.name);     // ignore error (may not exist)
  1064.     OSErr err = PBCatMoveSync( ¶mBlock );
  1065.     THROW_IF_ERROR( err );
  1066.  
  1067.     fFileSpec.parID = targetParID ;
  1068. }
  1069.  
  1070. //------------------------------------------------------------------------------
  1071. // PlatformFile::UniquifyName
  1072. // Given in this a platformfile (whose filespec only is used) that may conflict
  1073. // with an existing file, deal with this conflict in one of two ways depending
  1074. // on the value of action.  The two values are:
  1075. // 1. kSpecifyNewNameOnly: just change the name field of the filespec so that the
  1076. // platform file represents a file that would be unique if created
  1077. // 2. kRenameInPlace: this file already exists, but we want it to have a different
  1078. // name so we can reuse this one.  Find that name, and rename the actual file.
  1079. // 
  1080. // Two string templates are expected, and the caller can either pass in their
  1081. // resource IDs or StringHandles to the strings themselves, signifying the latter
  1082. // with a resource ID of kODNoResourceID.  The first of these strings is used
  1083. // the first time through the renaming loop (which typically sticks something
  1084. // like " copy" on the end of the file name, and the second is used thereafter
  1085. // (when increasingly large numbers are put into the string in an attempt to
  1086. // make it unique.
  1087. //------------------------------------------------------------------------------
  1088.  
  1089. void PlatformFile::UniquifyName( ODSShort uniquifyingStringID,
  1090.             StringHandle uniquifyingString, 
  1091.             ODSShort uniquifyingNumberID,
  1092.             StringHandle uniquifyingNumberString, 
  1093.             short copyCount,
  1094.             PFUniquifyAction action, 
  1095.             ODBoolean forceNewName)
  1096. {
  1097.     if ((forceNewName!=kODTryCurrentName) || this->Exists() )
  1098.     {
  1099.         PlatformFile* possibleOther = new PlatformFile;
  1100.         TempPlatformFile t = possibleOther;        // save so will get deconstructed
  1101. //        possibleOther->SpecifyFromFile( this );
  1102.     
  1103.         // Get the strings to be used in substitution if they weren't passed in.
  1104.         // Assign them to tempobjs so we don't have to dispose later.  Don't assign
  1105.         // if they're passed in (of course....)
  1106.         TempODHandle registerNoNumHandleIfLocal = kODNULL;
  1107.         TempODHandle registerNumHandleIfLocal = kODNULL;
  1108.         CUsingLibraryResources r;
  1109.         if ( uniquifyingStringID != kODNoResourceID )
  1110.         {
  1111.             WASSERT( !uniquifyingString );
  1112.             uniquifyingString = GetString( uniquifyingStringID );
  1113.             DetachResource( (Handle)uniquifyingString );
  1114.             registerNoNumHandleIfLocal = (Handle)uniquifyingString;
  1115.             WASSERT( uniquifyingString );
  1116.         }
  1117.         if ( uniquifyingNumberID != kODNoResourceID )
  1118.         {
  1119.             WASSERT(!uniquifyingNumberString);
  1120.             uniquifyingNumberString = GetString( uniquifyingNumberID );
  1121.             DetachResource( (Handle)uniquifyingNumberString );
  1122.             registerNumHandleIfLocal = (Handle)uniquifyingNumberString;
  1123.         }
  1124.         WASSERT(uniquifyingNumberString);
  1125.     
  1126.         ODFileSpec localCopy = this->GetFileSpec();
  1127.         // save the name (as we'll be munging localCopy)
  1128.         Str63 originalName;
  1129.         ODBlockMove( localCopy.name, originalName, localCopy.name[0]+1 );
  1130.     
  1131.         TempODHandle baseText = ODNewHandle(kMaxFileNameSize+1);
  1132.         THROW_IF_NULL(baseText);
  1133.         TempODHandle substitutionText = ODNewHandle(kMaxFileNameSize+1);
  1134.         THROW_IF_NULL(substitutionText);
  1135.     
  1136.         ODBoolean nameNeedsNumber = (uniquifyingString == kODNULL);
  1137.             // if there is no uniquifyingString, we immediately need to start using
  1138.             // the uniquifyingNumberString, or in other words nameNeedsNumber==true.
  1139.             
  1140.         for ( ; ; nameNeedsNumber = kODTrue)
  1141.         {
  1142.             // nameNeedsNumber = copyCount > 1;
  1143.             StringHandle templateToUse = nameNeedsNumber ?
  1144.                     uniquifyingNumberString : uniquifyingString;
  1145.     
  1146.             short thisTemplateLen = **templateToUse;
  1147.             // <eeh> NOTE that this forces callers to have two ^number tuples in the
  1148.             // second template.
  1149.             thisTemplateLen -= nameNeedsNumber? 4 : 2;
  1150.     
  1151.             short numberLen;
  1152.             Str32 numberString;
  1153.             if ( nameNeedsNumber )
  1154.             {
  1155.                 NumToString( copyCount, numberString );
  1156.                 numberLen = numberString[0];
  1157.             }
  1158.             else
  1159.                 numberLen = 0;
  1160.     
  1161.             // truncate the name if after appending it will be too long
  1162.             Str63 localName;
  1163.             ODBlockMove( originalName, localName, originalName[0] + 1 );
  1164.             short postAppendLen = localName[0] + thisTemplateLen + numberLen;
  1165.             if ( postAppendLen > kODMaxFileNameSize )
  1166.                 ClipStringToBytes( localName,
  1167.                         kODMaxFileNameSize - thisTemplateLen - numberLen, fScriptTag );
  1168.     
  1169.             // copy the template into the base handle, then pass in the possible file
  1170.             // name
  1171.             short len;
  1172.             SetHandleSize( baseText, len = **templateToUse );
  1173.             ODBlockMove( (*templateToUse)+1, *baseText, len );
  1174.             SetHandleSize( substitutionText, len = localName[0] );
  1175.             ODBlockMove( &localName[1], *substitutionText, len );
  1176.             short err = ReplaceText( baseText, substitutionText, "\p^0" );
  1177.             WASSERT( err >= 0 );
  1178.             
  1179.             if ( nameNeedsNumber )        // do same for number
  1180.             {
  1181.                 SetHandleSize( substitutionText, len = numberString[0] );
  1182.                 ODBlockMove( &numberString[1], *substitutionText, len );
  1183.                 err = ReplaceText( baseText, substitutionText, "\p^1" );
  1184.                 WASSERT( err >= 0 );
  1185.             }
  1186.     
  1187.             ODBlockMove( *baseText, &localCopy.name[1], len = GetHandleSize(baseText) );
  1188.             localCopy.name[0] = len;
  1189.     
  1190.             possibleOther->Specify( &localCopy );
  1191.             if ( !possibleOther->Exists() )
  1192.             {
  1193.                 WASSERT( localCopy.name[0] <= kODMaxFileNameSize );
  1194.                 if ( action == kSpecifyNewNameOnly )
  1195.                 {
  1196.                     // set up this so that when created it will represent a unique file
  1197.                     PascalToCString( localCopy.name );
  1198.                     this->SetAsciiName( (char*)localCopy.name );
  1199.                 }
  1200.                 else if ( action == kRenameInPlace )
  1201.                 {
  1202.                     // put the original file spec back in the target, then call
  1203.                     // Rename passing in the new name
  1204.                     WASSERT(this->Exists());
  1205.                     this->Rename( localCopy.name );
  1206.                 }
  1207.                 else
  1208.                     WARN( "unknown PFUniquifyAction" );
  1209.                 break;
  1210.             }
  1211.             if (nameNeedsNumber)
  1212.                 ++copyCount;        
  1213.                 // Gets executed after 2nd time through loop if there was a valid
  1214.                 // uniquifyString.  
  1215.                 // Otherwise gets executed after 1st time through loop.
  1216.         }
  1217.     }
  1218. }    // UniquifyName
  1219.  
  1220. //------------------------------------------------------------------------------
  1221. // PlatformFile::MoveToTrash
  1222. //------------------------------------------------------------------------------
  1223.  
  1224. void PlatformFile::MoveToTrash()
  1225. {
  1226.     ODSLong parID = fFileSpec.parID;
  1227.     ODSLong            trashDirID;
  1228.     THROW_IF_ERROR(FindFolder(fFileSpec.vRefNum, kTrashFolderType, kCreateFolder,
  1229.                             &(fFileSpec.vRefNum), &trashDirID));
  1230.                             
  1231.     // Move deletes any file that may conflict with the file once moved, but
  1232.     // in this case that isn't what we want.  So check if such a file exists,
  1233.     // and if so rename the conflicting file first (following the Finder's
  1234.     // model.)
  1235.     ODFileSpec possibleOtherFS = this->GetFileSpec();
  1236.     possibleOtherFS.parID = trashDirID;
  1237.     PlatformFile target;        // represents a file that *may* be in the trash
  1238.     target.Specify( &possibleOtherFS );
  1239.     
  1240. #if 1
  1241. //    if ( target.Exists() )
  1242.     {
  1243.         CUsingLibraryResources r;
  1244.         target.UniquifyName( kCopyDefaultNameNoNumStrID, kODNULL,
  1245.                 kCopyDefaultNameWithNumStrID, kODNULL, 2, kRenameInPlace,
  1246.                 kODTryCurrentName ) ;
  1247.     }
  1248. #else
  1249.     Str32 uniqueName;
  1250.     if ( MakeUniqueFileName( &target, kCopyDefaultNameNoNumStrID,
  1251.             kCopyDefaultNameWithNumStrID, 31, uniqueName ) )
  1252.         target.Rename( uniqueName );
  1253. #endif
  1254.     this->Move(trashDirID);
  1255.  
  1256.     CInfoPBRec pbRec;
  1257.     pbRec.hFileInfo.ioCompletion = NULL;
  1258.     pbRec.hFileInfo.ioNamePtr = fFileSpec.name;
  1259.     pbRec.hFileInfo.ioVRefNum = fFileSpec.vRefNum;
  1260.     pbRec.hFileInfo.ioFDirIndex = 0;
  1261.     pbRec.hFileInfo.ioDirID = fFileSpec.parID;
  1262.     
  1263.     
  1264.     if ( PBGetCatInfoSync( &pbRec ) == noErr )
  1265.     {
  1266.         // <eeh> stuffing this field *may* not work under Copland
  1267.         pbRec.hFileInfo.ioFlXFndrInfo.fdPutAway = parID;
  1268.         // this was changed by PBGetCatInfoSync...
  1269.         pbRec.hFileInfo.ioDirID = fFileSpec.parID;
  1270.         (void)PBSetCatInfoSync( &pbRec );    // ignore the error
  1271.     }
  1272. }
  1273.  
  1274. //------------------------------------------------------------------------------
  1275. // PlatformFile::Rename
  1276. //        This routine will not yet delete a file that will prevent the
  1277. //            renaming (as Move() does above.)
  1278. //------------------------------------------------------------------------------
  1279. void PlatformFile::Rename( Str63 newName )
  1280. {
  1281.     this->UpdateSpecFromID();
  1282.     
  1283.     THROW_IF_ERROR( FSpRename( &fFileSpec, newName ) );
  1284.      CopyPascalString(fFileSpec.name, newName);
  1285.     BumpFolderModDate();
  1286. }
  1287.  
  1288.  
  1289. //------------------------------------------------------------------------------
  1290. // PlatformFile::GetFileModDate
  1291. //        This routine will set the file modification date to the input parameter
  1292. //------------------------------------------------------------------------------
  1293. ODTime PlatformFile::GetFileModDate()
  1294. {
  1295.     this->UpdateSpecFromID();
  1296.     
  1297.     CInfoPBRec    pbBlock;
  1298.     pbBlock.hFileInfo.ioCompletion = kODNULL;
  1299.     pbBlock.hFileInfo.ioFDirIndex = 0;
  1300.     pbBlock.hFileInfo.ioNamePtr = fFileSpec.name;
  1301.     pbBlock.hFileInfo.ioVRefNum = fFileSpec.vRefNum;
  1302.     pbBlock.hFileInfo.ioDirID = fFileSpec.parID;
  1303.     THROW_IF_ERROR(PBGetCatInfoSync(&pbBlock));
  1304.     return pbBlock.hFileInfo.ioFlMdDat;
  1305. }
  1306.  
  1307.  
  1308. //------------------------------------------------------------------------------
  1309. // PlatformFile::SetFileModDate
  1310. //        This routine will set the file modification date to the input parameter
  1311. //------------------------------------------------------------------------------
  1312. void PlatformFile::SetFileModDate(ODTime date)
  1313. {
  1314.     this->UpdateSpecFromID();
  1315.     
  1316.     if (!this->IsLocked()) {
  1317.         CInfoPBRec    pbBlock;
  1318.         pbBlock.hFileInfo.ioCompletion = kODNULL;
  1319.         pbBlock.hFileInfo.ioFDirIndex = 0;
  1320.         pbBlock.hFileInfo.ioNamePtr = fFileSpec.name;
  1321.         pbBlock.hFileInfo.ioVRefNum = fFileSpec.vRefNum;
  1322.         pbBlock.hFileInfo.ioDirID = fFileSpec.parID;
  1323.         if (PBGetCatInfoSync(&pbBlock) == noErr) {
  1324.             pbBlock.hFileInfo.ioDirID = fFileSpec.parID;
  1325.             pbBlock.hFileInfo.ioFlMdDat = date;
  1326.             (void) PBSetCatInfoSync(&pbBlock); /* who cares if it fails */
  1327.         }
  1328.     }
  1329. }
  1330.  
  1331. //------------------------------------------------------------------------------
  1332. // PlatformFile::SetFileCreationDate
  1333. //        This routine will set the file creation date to the input parameter
  1334. //------------------------------------------------------------------------------
  1335. void PlatformFile::SetFileCreationDate(ODTime date)
  1336. {
  1337.     this->UpdateSpecFromID();
  1338.  
  1339.     CInfoPBRec    pbBlock;
  1340.  
  1341.     if (!this->IsLocked()) {
  1342.         pbBlock.hFileInfo.ioCompletion = kODNULL;
  1343.         pbBlock.hFileInfo.ioFDirIndex = 0;
  1344.         pbBlock.hFileInfo.ioNamePtr = fFileSpec.name;
  1345.         pbBlock.hFileInfo.ioVRefNum = fFileSpec.vRefNum;
  1346.         pbBlock.hFileInfo.ioDirID = fFileSpec.parID;
  1347.         if (PBGetCatInfoSync(&pbBlock) == noErr) {
  1348.             pbBlock.hFileInfo.ioDirID = fFileSpec.parID;
  1349.             pbBlock.hFileInfo.ioFlCrDat = date;
  1350.             (void) PBSetCatInfoSync(&pbBlock); /* who cares if it fails */
  1351.         }
  1352.     }
  1353. }
  1354.                 
  1355. //------------------------------------------------------------------------------
  1356. // PlatformFile::GetFileCreationDate
  1357. //        This routine will get the file creation date and return it.
  1358. //------------------------------------------------------------------------------
  1359. ODTime PlatformFile::GetFileCreationDate()
  1360. {
  1361.     this->UpdateSpecFromID();
  1362.     
  1363.     CInfoPBRec    pbBlock;
  1364.     pbBlock.hFileInfo.ioCompletion = kODNULL;
  1365.     pbBlock.hFileInfo.ioFDirIndex = 0;
  1366.     pbBlock.hFileInfo.ioNamePtr = fFileSpec.name;
  1367.     pbBlock.hFileInfo.ioVRefNum = fFileSpec.vRefNum;
  1368.     pbBlock.hFileInfo.ioDirID = fFileSpec.parID;
  1369.     THROW_IF_ERROR(PBGetCatInfoSync(&pbBlock));
  1370.     return pbBlock.hFileInfo.ioFlCrDat;
  1371. }
  1372.             
  1373. //------------------------------------------------------------------------------
  1374. // PlatformFile::BumpFolderModDate
  1375. //        This routine will set the file modification date of the parent folder
  1376. //        to the current time so as to cause the Finder to refresh the folder if
  1377. //        it is open.  It only has WARNs if it errors.
  1378. //------------------------------------------------------------------------------
  1379. void PlatformFile::BumpFolderModDate()
  1380. {
  1381.     CInfoPBRec    theParamBlock;
  1382.  
  1383.     memset (&theParamBlock, 0, sizeof(theParamBlock));
  1384.     // ioNamePtr = 0
  1385.     theParamBlock.dirInfo.ioFDirIndex = -1;
  1386.     theParamBlock.dirInfo.ioVRefNum = fFileSpec.vRefNum;
  1387.     theParamBlock.dirInfo.ioDrDirID = fFileSpec.parID;
  1388.     OSErr err = PBGetCatInfoSync(&theParamBlock);
  1389.     if( err )
  1390.         WARN("Couldn't get dir mod date, err %hd",err);
  1391.     else
  1392.     {
  1393.         ODULong newTime;
  1394.  
  1395.         GetDateTime(&newTime);
  1396.         // set to the future if it is now
  1397.         if (theParamBlock.dirInfo.ioDrMdDat >= newTime)
  1398.             ++newTime;
  1399.         theParamBlock.dirInfo.ioDrMdDat = newTime;
  1400.         err = PBSetCatInfoSync(&theParamBlock);
  1401.         if( err )
  1402.             WARN("Couldn't bump dir mod date, err %hd",err);
  1403.     }
  1404. }
  1405.                 
  1406. //------------------------------------------------------------------------------
  1407. // PlatformFile::GetFirstLocalPath
  1408. //------------------------------------------------------------------------------
  1409.  
  1410. ODFileRefNum PlatformFile::GetFirstLocalPath( ODForkType fork )
  1411. {
  1412.     ODFileSpec* spec = &fFileSpec;
  1413.     
  1414.     OSErr        result;
  1415.     FCBPBRec    pb;
  1416.     short        index;
  1417.     Str31        tempName;
  1418.     
  1419.     /* Get FCB name in tempName */
  1420.     pb.ioNamePtr = tempName;
  1421.     
  1422.     /* Index through the open paths on the volume specified by fFileSpec.vRefNum */
  1423.     pb.ioVRefNum = fFileSpec.vRefNum;
  1424.     index = 1;
  1425.     do
  1426.     {
  1427.         pb.ioRefNum = 0;
  1428.         pb.ioFCBIndx = index;
  1429.         result = PBGetFCBInfoSync(&pb);
  1430.         if ( result == noErr )
  1431.         {
  1432.             /*
  1433.             **    See if parent directory ID matches and
  1434.             **    file name matches and
  1435.             **    the file fork (resource or data) matches
  1436.             */
  1437.             if ( (pb.ioFCBParID == fFileSpec.parID) &&
  1438.                  EqualString(fFileSpec.name, tempName, false, true) &&
  1439.                  ((fork == kODResourceFork) == ((pb.ioFCBFlags & (1 << 9)) != 0)) )
  1440.             {
  1441.                 return pb.ioRefNum;            // Found it!
  1442.             }
  1443.             ++index;    /* next FCB index */
  1444.         }
  1445.     } while ( result == noErr );
  1446.     
  1447.     return kODNoFileRefNum;
  1448. }
  1449.  
  1450.  
  1451. //------------------------------------------------------------------------------
  1452. // PlatformFile::GetLocalPaths
  1453. //------------------------------------------------------------------------------
  1454.  
  1455. ODError        PlatformFile::GetLocalPaths(
  1456.                               ODForkType fork,
  1457.                               ODULong *refNumCount,
  1458.                               ODFileRefNumPtr *refNums)
  1459. {
  1460.     const ODULong kMaxFCBs = 348;    /* The maximum number of local access paths under System 7 */
  1461.     
  1462.     OSErr        result;
  1463.     FCBPBRec    pb;
  1464.     short        index;
  1465.     Str31        tempName;
  1466.     ODFileRefNumPtr    tempRefNums;
  1467.     
  1468.     /* initialize returned values */
  1469.     *refNumCount = 0;
  1470.     *refNums = NULL;
  1471.     
  1472.     /* Allocate temp storage for refNum matches */
  1473.     tempRefNums = (ODFileRefNumPtr)ODNewPtr(kMaxFCBs * sizeof(short));
  1474.     
  1475.     if ( tempRefNums != NULL )
  1476.     {
  1477.         /* Get FCB name in tempName */
  1478.         pb.ioNamePtr = tempName;
  1479.         
  1480.         /* Index through the open paths on the volume specified by fFileSpec.vRefNum */
  1481.         pb.ioVRefNum = fFileSpec.vRefNum;
  1482.         index = 1;
  1483.         do
  1484.         {
  1485.             pb.ioRefNum = 0;
  1486.             pb.ioFCBIndx = index;
  1487.             result = PBGetFCBInfoSync(&pb);
  1488.             if ( result == noErr )
  1489.             {
  1490.                 /*
  1491.                 **    See if parent directory ID matches and
  1492.                 **    file name matches and
  1493.                 **    the file fork (resource or data) matches
  1494.                 */
  1495.                 if ( (pb.ioFCBParID == fFileSpec.parID) &&
  1496.                      EqualString(fFileSpec.name, tempName, false, true) &&
  1497.                      ((fork == kODResourceFork) == ((pb.ioFCBFlags & (1 << 9)) != 0)) )
  1498.                 {
  1499.                     /* It's a match - add it to the array of matches */
  1500.                     tempRefNums[*refNumCount] = pb.ioRefNum;
  1501.                     ++(*refNumCount);
  1502.                 }
  1503.                 ++index;    /* next FCB index */
  1504.             }
  1505.         } while ( result == noErr );
  1506.         
  1507.         /* These errors are OK - they mean we hit the end of the FCB list */
  1508.         if ( (result == rfNumErr) || (result == fnOpnErr) )
  1509.         {
  1510.             result = noErr;
  1511.         }
  1512.         
  1513.         if ( (result == noErr) && (*refNumCount != 0) )
  1514.         {
  1515.             // Note: the below two lines were a gratuitous change from the tested code
  1516.             // given to me by Jim Luther.  Therefore I have commented them out and returned
  1517.             // the original code. -Tantek
  1518.             //*refNums = (ODFileRefNumPtr) ODReallocate( tempRefNums, *refNumCount * sizeof(short) );
  1519.             //*tempRefNums = kODNULL;
  1520.             /* Allocate memory to return refNum matches in */
  1521.             *refNums = (ODFileRefNumPtr)ODNewPtr(*refNumCount * sizeof(short));
  1522.             if ( *refNums != NULL )
  1523.             {
  1524.                 /* Move refNums from tempRefNums to *refNums */
  1525.                 ODBlockMove((Ptr)tempRefNums, (Ptr)*refNums, (*refNumCount * sizeof(short)));
  1526.             }
  1527.             else
  1528.             {
  1529.                 /* Couldn't allocate memory for refNum array */
  1530.                 result = memFullErr;
  1531.             }
  1532.  
  1533.         }
  1534.         
  1535.         /* Free up tempRefNums storage */ 
  1536.         ODDisposePtr((Ptr)tempRefNums);
  1537.     }
  1538.     else
  1539.     {
  1540.         /* Couldn't allocate temp memory */
  1541.         result = memFullErr;
  1542.     }
  1543.     
  1544.     return ( result );
  1545. }
  1546.  
  1547. //------------------------------------------------------------------------------
  1548. // PlatformFile::GetComments
  1549. //
  1550. //    If a pointer is passed in, the text is placed there and a pointer to it is
  1551. //    returned.  If the comments pointer is null, then a new pointer is allocated
  1552. //    and returned.
  1553. //------------------------------------------------------------------------------
  1554.  
  1555. enum {
  1556.     uppPBDTInfo = kRegisterBased
  1557.          | RESULT_SIZE(sizeof(OSErr))
  1558.          | REGISTER_RESULT_LOCATION(kRegisterD0)
  1559.          
  1560.          | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(kTwoByteCode))    // trap word
  1561.          | REGISTER_ROUTINE_PARAMETER(2, kRegisterD0, SIZE_CODE(kTwoByteCode))    // selector
  1562.          
  1563.          | REGISTER_ROUTINE_PARAMETER(3, kRegisterA0, SIZE_CODE(sizeof(DTPBRec*)))
  1564.          | REGISTER_ROUTINE_PARAMETER(4, kRegisterA3, SIZE_CODE(sizeof(void*)))
  1565. };
  1566.  
  1567. #if GENERATING68K && GENERATINGCFM
  1568. OSErr PBDTGetCommentSyncGlue(DTPBRec *pb);
  1569. OSErr PBDTGetCommentSyncGlue(DTPBRec *pb)
  1570. {
  1571.     void* hfsdispatch = GetOSTrapAddress(0xA260);
  1572.     return CallOSTrapUniversalProc((UniversalProcPtr) hfsdispatch,
  1573.                                     uppPBDTInfo,
  1574.                                     (short) 0xA260,    // trap word
  1575.                                     (short) 0x002A,    // selector
  1576.                                     pb,                // a1, the param block ptr
  1577.                                     pb                // a3 should be ignored
  1578.                                   );
  1579. }
  1580. #endif
  1581.  
  1582. #if GENERATING68K && GENERATINGCFM
  1583. OSErr PBDTSetCommentSyncGlue(DTPBRec *pb);
  1584. OSErr PBDTSetCommentSyncGlue(DTPBRec *pb)
  1585. {
  1586.     void* hfsdispatch = GetOSTrapAddress(0xA260);
  1587.     return CallOSTrapUniversalProc((UniversalProcPtr) hfsdispatch,
  1588.                                     uppPBDTInfo,
  1589.                                     (short) 0xA260,    // trap word
  1590.                                     (short) 0x0028,    // selector
  1591.                                     pb,                // a1, the param block ptr
  1592.                                     pb                // a3 should be ignored
  1593.                                   );
  1594. }
  1595. #endif
  1596.  
  1597. ODIText*    PlatformFile::GetComments(ODIText* comments)
  1598. {
  1599.     DTPBRec            pb;    
  1600.     memset( &pb, 0, sizeof(pb) );
  1601.     
  1602.     pb.ioVRefNum = fFileSpec.vRefNum;
  1603.     OSErr err = PBDTGetPath(&pb);
  1604.     if (err == noErr)
  1605.     {
  1606.         pb.ioNamePtr = fFileSpec.name;
  1607.         pb.ioDirID = fFileSpec.parID;
  1608.         char buffer[256];
  1609.         pb.ioDTBuffer = buffer;
  1610.  
  1611.         // avoid the crash on 68K if the PlatformFile is remote
  1612. #if GENERATING68K && GENERATINGCFM
  1613.         err = PBDTGetCommentSyncGlue(&pb);
  1614. #else
  1615.         err = PBDTGetCommentSync(&pb);
  1616. #endif
  1617.         if (err == noErr) {
  1618.             buffer[pb.ioDTActCount] = 0; // make it a c string
  1619.             if (comments == kODNULL)
  1620.             {
  1621.                 ODScriptCode script = FontToScript( GetSysFont() );
  1622.                 comments = CreateITextCString(script, 
  1623.                         GetScriptVariable( script, smScriptLang ), buffer);
  1624.             }
  1625.             else
  1626.                 SetITextCString(comments, buffer);
  1627.         }
  1628.     }
  1629.     
  1630.     return comments;
  1631. }
  1632.  
  1633. //------------------------------------------------------------------------------
  1634. // PlatformFile::SetComments
  1635. //------------------------------------------------------------------------------
  1636.  
  1637. void
  1638. PlatformFile::SetComments(ODIText* comments)
  1639. {
  1640.     DTPBRec        pb;
  1641.     OSErr        err = noErr;    // PBDTGetPath seems not to return anything,
  1642.                                 // so must init
  1643.     
  1644.     pb.ioNamePtr = kODNULL;
  1645.     pb.ioVRefNum = fFileSpec.vRefNum;
  1646.     err = PBDTGetPath(&pb);
  1647.     if (err == noErr)
  1648.     {
  1649.         Str255    commentStr;
  1650.             
  1651.         pb.ioNamePtr = fFileSpec.name;
  1652.         pb.ioDirID = fFileSpec.parID;
  1653.         pb.ioDTBuffer = (char *)&commentStr[1];
  1654.         if (comments) {
  1655.             
  1656.             ODULong numBytes = GetITextStringLength(comments);
  1657.             if (numBytes > kMaxCommentSize) {
  1658.                 GetITextPString(comments, commentStr);
  1659.                 pb.ioDTReqCount = ClipStringToBytes(commentStr, kMaxCommentSize,
  1660.                                                     GetITextScriptCode(comments) );
  1661.             } else {
  1662.                 pb.ioDTBuffer = GetITextPtr(comments);
  1663.                 pb.ioDTReqCount = numBytes;
  1664.             }
  1665.         }
  1666.         else
  1667.             pb.ioDTReqCount = 0;
  1668.         // avoid the crash on 68K if the PlatformFile is remote
  1669. #if GENERATING68K && GENERATINGCFM
  1670.         err = PBDTSetCommentSyncGlue(&pb);
  1671. #else
  1672.         err = PBDTSetCommentSync(&pb);
  1673. #endif
  1674.         }
  1675. }
  1676.  
  1677. //------------------------------------------------------------------------------
  1678. // PlatformFile::GetCustomIconFamily
  1679. //------------------------------------------------------------------------------
  1680.  
  1681. ODIconFamily
  1682. PlatformFile::GetCustomIconFamily()
  1683. {
  1684.     ODIconFamily icons = kODNULL; ODVolatile(icons);
  1685.     
  1686.     if (HasCustomIcon())
  1687.     {
  1688.         // read icons from the file
  1689.         SetPermission(fsRdPerm);
  1690. //        OpenResFile();
  1691.         TRY
  1692.             for( long i=5; i>=0; i-- )
  1693.             {
  1694.                 ODULong    size;
  1695.                 TempODPtr ptr = this->ReadResourcePtr(kIconType[i], kCustomIconResource, &size);
  1696.                 if (ptr != kODNULL)
  1697.                 {
  1698.                     if (icons == kODNULL)
  1699.                         THROW_IF_ERROR( NewIconSuite(&icons) );
  1700.                     Handle icon = (Handle) ODNewHandle(size);
  1701.                     ODBlockMove(ptr,*icon,size);
  1702.                     OSErr err = AddIconToSuite(icon, icons, kIconType[i]);
  1703.                     if( err ) {
  1704.                         ODDisposePtr(icon);
  1705.                         THROW(err);
  1706.                     }
  1707.                 }
  1708.             }
  1709.         CATCH_ALL
  1710.             WARN("Ignoring error %ld",ErrorCode());
  1711.             if( icons ) DisposeIconSuite(icons,kODTrue);
  1712.         ENDTRY
  1713. //        CloseResFile();
  1714.     }
  1715.     return icons;
  1716. }
  1717.  
  1718. //------------------------------------------------------------------------------
  1719. // PlatformFile::SetCustomIconFamily
  1720. //------------------------------------------------------------------------------
  1721.  
  1722. void
  1723. PlatformFile::SetCustomIconFamily(ODIconFamily icons)
  1724. {
  1725.     // set with kODNULL as the icons to delete the custom icons
  1726.     TRY
  1727.         if (!icons)
  1728.         {
  1729.             // check to see if there's a resFile so that we don't
  1730.             // create one while trying to delete nonexistant icons
  1731.             SetPermission(fsRdPerm);
  1732.             OpenResFile();        // THROW if no resFile
  1733.             CloseResFile();
  1734.         }
  1735.         // write icons to the file
  1736.         SetPermission(fsRdWrPerm);
  1737.         OpenResFile();
  1738.         for( long i=5; i>=0; i-- )
  1739.         {
  1740.             Handle    icon;
  1741.             char    state;
  1742.             
  1743.             if( icons )
  1744.                 THROW_IF_ERROR( GetIconFromSuite(&icon, icons, kIconType[i]) );
  1745.             else
  1746.                 icon = kODNULL;
  1747.             if (icon)
  1748.             {
  1749.                 state = HGetState(icon);
  1750.                 HLock(icon);
  1751.                 WASSERT(GetHandleSize(icon) == kIconSize[i]);
  1752.                 WriteResourcePtr(kIconType[i], kCustomIconResource, *icon, kIconSize[i]);
  1753.                 HSetState(icon, state);
  1754.             } else
  1755.                 DeleteResource(kIconType[i], kCustomIconResource);
  1756.         }
  1757.         CloseResFile();
  1758.     CATCH_ALL
  1759.     ENDTRY
  1760.     SetCustomIcon(icons != kODNULL);
  1761. }
  1762.